package client;
//package graphics;
/*
 * Code source sour licence MIT
 * HEIG-VD
 */


import communication.game.CellsPlayed;
import communication.game.ConfirmGameCreated;
import communication.game.ConfirmGameJoined;
import communication.game.GameClosed;
import communication.game.NextPlayer;
import game.Game;
import game.GameObject;
import game.MagicObject;
import game.Player;
import communication.game.GameStarted;
import communication.game.ConfirmGameFinished;

import javax.swing.*;

import java.awt.event.*;
import java.util.*;


/**
 *
 * @author CONSTANTIN Laurent, Julien Roch
 * @version 1.0
 */

public class ClientView implements Observer {
	// Les vues internes du client.
	// Elles sont instancies une fois. Et masquees / affichees apres
    private JPanelConnect connectWindow ;
    private JPanelListGame gamesWindow ;
    private JPanelLogin loginWindow;
    private JPanelNewAccount newAccountWindow;
    private JPanelConfigGame configGame;
    private JPanelGrid gameGrid;
    private JPanelGame jpg;
    private JPanelMagicObjects magObj;
    private boolean hasToPack=true;
    
    // Fenetre qui contient les JPanels
    private JWin window;

    
    final ClientApplication clientApp;
    /**
     * Instancie les vues clients sans rien afficher
     * @param clientApp L'application appelante
     */
    public ClientView(ClientApplication clientApp){
    	this.clientApp = clientApp;
        
    	// Instancie les vues
    	connectWindow = new JPanelConnect(clientApp);
        gamesWindow = new JPanelListGame(clientApp);
        loginWindow = new JPanelLogin(clientApp);
        newAccountWindow = new JPanelNewAccount(clientApp);
        configGame = new JPanelConfigGame(clientApp);

        window = new JWin();
		// Code lors du clique sur le bouton de fermeture
		window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		window.addWindowListener(new WindowAdapter() {
			
			/**
			 * Confirmation pour quitter
			 */
			public void windowClosing(WindowEvent e) {
				
				if (JOptionPane.showConfirmDialog(ClientView.this.window,
						"Etes vous sur de vouloir quitter l'application?",
						"Quitter?", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION
				){
						if (ClientView.this.clientApp.netClient.isConnected())
							ClientView.this.clientApp.disconnect();
						System.exit(0);
				}
			}
		});        
    }
    /**
     * Obtient la vue courrament affichee
     * @return La vue affichee (Jpanel)
     */
    public JPanel getCurrentPanel(){
    	return window.currentPannel;
    }
    /**
     * Affiche la vue de connection au serveur
     */
    public void showConnectDialog(){
        window.setPannel(connectWindow);
    }
    /**
     * Affiche la vue qui liste les jeux
     */
    public void showListGameDialog(){
        window.setPannel(gamesWindow);
    }
    /**
     * Affiche la vue de login
     */
    public void showLoginDialog(){
    	window.setPannel(loginWindow);
    	loginWindow.setFocus();
    }
    /**
     * Affiche la vue de creation de compte
     */
    public void showNewAccountDialog(){
    	window.setPannel(newAccountWindow);
    }
    /**
     * Obtient le conteneur de vue (la fenetre)
     * @return JWin
     */
    public JWin getInternalView(){
    	return window;
    }
    /**
     * Masque la fenetre
     */
    public void hide(){
    	window.setVisible(false);
    }
	/**
	 * Permet d'afficher la vue de configuration de nouvelle partie
	 */
	public void showConfigGame() {
		window.setResizable(false);
		window.setPannel(configGame);
		configGame.setFocus();
	}
    
	/**
	 * Permet d'afficher la vue de debriefing
	 * @param game Objet de fin de jeu
	 */
	public void showDebriefing(ConfirmGameFinished game) {
		window.setResizable(false);		
		window.setPannel(new JPanelDebriefing(clientApp, game));
	}
	/**
	 * Permet d'afficher la vue de briefing
	 * @param game La partie a afficher 
	 */
	public void showBriefing(Game game) {
		window.setResizable(false);
		window.setPannel(new JPanelBriefing(clientApp, game));
	}
	
	/**
	 * Permet d'afficher la vue du jeu
	 * @param game la partie
	 * @param players la liste des joueurs
	 */
	public void showViewGame(Game game, Player[] players) {
		window.setResizable(true);
		jpg = new JPanelGame(clientApp, game, players);
		magObj = jpg.getObjects();
		this.gameGrid = jpg.getGrid();
		window.setPannel(jpg,false);
	}
	
	/**
	 * Permet de changer la position de la fenetre
	 * @param x
	 * @param y
	 */
    public void setPosition(int x, int y){
    	window.setLocation(x, y);
    	window.repaint();
    }
  
    /**
     * Fenetre de la vue client. Contient un Jpanel qui change suivant la vue
     */
    class JWin extends JFrame {
		private static final long serialVersionUID = -9195097278983449120L;
		private JPanel currentPannel;
        private JScrollPane scroll;
        
        /**
         * Constructeur
         */
        public JWin(){
            setTitle("Deminet v" + SettingsClient.VERSION);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);
           
            
            /**
             * Debug affiche taille de la fenetre en console
             */
            this.setResizable(false);
            /*this.setResizable(true);
            addComponentListener(new ComponentAdapter(){
            	public void componentResized(ComponentEvent e){
            		System.out.println("JFrame was resized " + e);
        		}
        	});*/
            
        }
        
        /**
         * Change le JPanel affiche dans la fenetre 
         * @param p Le panel a afficher
         */
        public void setPannel(JPanel p){
        	setPannel(p,true);
        }
        /**
         * Change le JPanel affiche dans la fenetre 
         * @param p Le panel a afficher
         * @param addScroll indique si il faut ajouter un scrollPane
         */
        public void setPannel(JPanel p, boolean addScroll){
           
            if(currentPannel != p && p != null){
            	if(addScroll){
                currentPannel = p;
                scroll = new JScrollPane(p);
                getContentPane().removeAll();
                getContentPane().add(scroll);
            	}else{
            		getContentPane().removeAll();
                    getContentPane().add(p);
            	}
            }
            pack();
            repaint();
            setVisible(true);
        }
    }



	@Override
	/**
	 * Dispatch les evenements aux pannels adequats
	 */
	public void update(Observable arg0, Object o) {
		// Intercepte si c'est une confirmation de creation de partie
		if (ConfirmGameCreated.class.isInstance(o)) {
			this.showBriefing(((ConfirmGameCreated)o).getGame());
			this.hasToPack = true;
		}
		// ou si c'est une confirmation de rejoignement de partie
		else if (ConfirmGameJoined.class.isInstance(o)) {
			this.showBriefing(((ConfirmGameJoined)o).getGame());
			this.hasToPack = true;
		}
		// ou si c'est un debut de partie
		else if (GameStarted.class.isInstance(o)) {
			this.showViewGame(((GameStarted)o).getGame(),
					((GameStarted)o).getPlayers());
			this.hasToPack = false;
		}
		else if (ConfirmGameFinished.class.isInstance(o)) {
			this.showDebriefing((ConfirmGameFinished)o);
			this.hasToPack = true;
		}
		// ou si c'est une partie du jeu
		else if (CellsPlayed.class.isInstance(o)) {
			hasToPack = false;
			
			if (this.gameGrid != null) {
				this.jpg.refreshPlayersScores(((CellsPlayed)o).getPlayers(),
						clientApp.internals.getNextPlayer());

				this.gameGrid.setPlayedGrid((CellsPlayed)o);
				for(GameObject ob : ((CellsPlayed)o).getObjects()){
					if(MagicObject.class.isInstance(ob)){
						((MagicObject)ob).HandleClientInternals(clientApp.internals);
					}
				}
				if(this.magObj!=null){
					magObj.refresh();
				}
			}
		}
		// ou si on specifie le prochain joueur
		else if (NextPlayer.class.isInstance(o)) {
			this.hasToPack = false;
			if (jpg != null)
				this.jpg.setCurrentPlayer(((NextPlayer)o).getPlayer());
		}
		// ou si une partie est fermee par le createur
		else if (GameClosed.class.isInstance(o)) {
			this.hasToPack = true;
			this.showListGameDialog();
		}

		gamesWindow.update(arg0, o);
		/*
		connectWindow.update(arg0, o);
		loginWindow.update(arg0, o);
        newAccountWindow.update(arg0, o);
        configGame.update(arg0, o);
        debriefing.update(arg0, o);
        */	
		if(hasToPack)
			window.pack();
		window.repaint();
	}
}
